/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.util;

/**
   This class implements some of the utilies commonly used during performance
   measurements on links and by other programs.

   @author Shrideep Pallickara
   $Date$
   $Revision$
*/

public class StatUtils {

  private static long[] 
  getMaxValues(long [] values, int numOfValues, int maxReject) {
    long[] maxValues = new long[maxReject];
    for (int i=0; i < maxReject; i++) {
      maxValues[i] = (long)0;
    }
    for (int i=0; i < numOfValues; i++) {
      for (int j=0; j < maxReject; j++) {
	if (values[i] >= maxValues[maxReject-1-j]) {
	  for (int k=0; k< maxReject-1-j; k++) {
	    maxValues[k] = maxValues[k+1];
	  }/*(k)*/
	  maxValues[maxReject-1-j] = values[i];
	  break;
	}/** if statement - for reorganizing the max array */
      }/*(j)*/
    }/*(i)*/

    return maxValues;
  } 


  /** This method computes the standard error of the mean based on the 
      standard deviation and the num of samples in the original sample. The
      standard error is the ratio of the standard deviation to the square root
      of the number of samples. */
  public static double 
  computeStandardErrorOfMean(double standardDeviation, int numOfSamples) {
    double standardError = standardDeviation/Math.sqrt( (double) numOfSamples);
    return standardError;
  }



  
  public static double 
  computeMean(long [] values, int numOfValues, int maxReject) {
    long[] maxValues = getMaxValues(values, numOfValues, maxReject);
    
    long addValues=0;
    double meanValue=0;
    
    for(int i=0; i <numOfValues; i++) {
      addValues+= values[i];
    }
    for (int i=0; i < maxReject; i++) {
      addValues-= maxValues[i];
    }
    
    meanValue =
      (double)addValues/(double)(numOfValues-maxReject);
    return meanValue;
  } /* end compute mean value*/


  public static double 
  computeStandardDeviation(long [] values, int numOfValues, int maxReject) {
    double meanValue = computeMean(values, numOfValues, maxReject);
    long[] maxValues = getMaxValues(values, numOfValues, maxReject);

    double squaredDifferenceOfMeanAndSample = 0;
    for (int i = 0; i< numOfValues; i++) {
      squaredDifferenceOfMeanAndSample +=
	(Math.pow((values[i]- meanValue),2) );
    }

    for (int i = 0; i < maxReject; i++) {
      squaredDifferenceOfMeanAndSample -=
	(Math.pow((maxValues[i]- meanValue),2) );
    }
    
    double variance =
      squaredDifferenceOfMeanAndSample/(numOfValues-maxReject-1);
    double stdDeviation = Math.sqrt(variance);
    return stdDeviation;
  } /* end compute standard deviation */



  /** Computes the jitter based on previous jitter, and current inter-packet
      arrival times. */
  public static double computeJitter(double jitter, double delayD, 
				     double delayDplusOne) {
    
    jitter +=  ( Math.abs( (double)(delayD - delayDplusOne) ) - jitter )/16;
    return jitter;
  }
  

  
  /** This method computes the standard deviation within a sample of values by
      first removing the outliers. */
  public static double
  computeStandardDeviationWithoutOutliers(long [] values, int numOfValues){
    double zValue=3;
    long [] outliers=new long[numOfValues];
    int counterO=0;
    double meanValue = computeMean(values, numOfValues, 0);
    double std=computeStandardDeviation(values, numOfValues, 0);
    if (std==0) return std;
    else{
      for (int i = 0; i < numOfValues; i++) {
        if (Math.abs( (values[i] - meanValue)) / std > zValue) {
          outliers[counterO] = values[i];
          counterO++;
        }
      }
      long[] newValues = new long[numOfValues - counterO];
      int counter = 0;
      for (int i = 0; i < numOfValues; i++) {
        if (!isOutlier(values[i], outliers)) {
          newValues[counter] = values[i];
          counter++;
        }

      }
      meanValue = computeMean(newValues, newValues.length, 0);
      std = computeStandardDeviation(newValues, newValues.length, 0);
      return std;
    }
  }

  /** This method computes the mean of a sample of values by first removing
      the outliers. */
  public static double 
  computeMeanWithoutOutliers(long [] values, int numOfValues) {
    double zValue=3;
    long [] outliers=new long[numOfValues];
    int counterO=0;
    double meanValue = computeMean(values, numOfValues, 0);
    double std=computeStandardDeviation(values, numOfValues, 0);
    if (std==0) return meanValue;
    else{
      for (int i = 0; i < numOfValues; i++) {
        if (Math.abs( (values[i] - meanValue)) / std > zValue) {
          outliers[counterO] = values[i];
          counterO++;
        }
      }
      long[] newValues = new long[numOfValues - counterO];
      int counter = 0;
      for (int i = 0; i < numOfValues; i++) {
        if (!isOutlier(values[i], outliers)) {
          newValues[counter] = values[i];
          counter++;
        }

      }
      meanValue = computeMean(newValues, newValues.length, 0);
      return meanValue;
    }
  } /* end compute mean value*/



  private static boolean isOutlier(long value, long[] outlier){
    for (int i=0; i<outlier.length;i++){
      if (value==outlier[i]) return true;
    }
    return false;

  }

  /** This method removes outliers from a sample of values. The samples 
      returned are the ones that do not contain the outliers. The size of the
      returned array MAY or MAY NOT be less than the original array. */
  public static long [] 
  getValuesWithoutOutliers(long[]values, int numOfValues){
    double zValue=2;
    long[] temp = new long[numOfValues];
    int counterO = 0;
    double meanValue = computeMean(values, numOfValues, 0);
    double std=computeStandardDeviation(values, numOfValues, 0);

    if (std==0) {
      long [] newArray=new long [numOfValues];
      for (int i = 0; i < newArray.length; i++) {
        newArray[i]=values[i];
      }
      return newArray;
    }
    
    for (int i = 0; i < numOfValues; i++) {
      if (Math.abs( (values[i] - meanValue)) / std > zValue) {
	temp[counterO] = values[i];
	counterO++;
      }
    }
    
    long [] outliers=new long[counterO];
    for (int i = 0; i < counterO; i++) {
      outliers[i]=temp[i];
    }
    long[] newValues = new long[numOfValues - counterO];
    int counter = 0;
    for (int i = 0; i < numOfValues; i++) {
      if (!isOutlier(values[i], outliers)) {
	newValues[counter] = values[i];
	counter++;
      }
    }
    return newValues;
  }


  public static void main(String[] args) {

    long [] values={10,3,2,4,2,2,2,2,2,9};
    System.out.println("average is "+ computeMean(values, 10, 0));
    System.out.println("StandardDeviation is "+ 
		       computeStandardDeviation(values, 10, 0));
    System.out.println("AVGNEW is "+ computeMeanWithoutOutliers(values, 10));
    System.out.println("StandardDeviation is "+ 
		       computeStandardDeviationWithoutOutliers(values, 10));
    long [] values1={10,0,0,0,0,0,0,0,0,1};
    System.out.println("average is "+ computeMean(values1, 10, 0));
    System.out.println("StandardDeviation is "+ 
		       computeStandardDeviation(values1, 10, 0));
    System.out.println("AVGNEW is "+ computeMeanWithoutOutliers(values1, 10));
    System.out.println("StandardDeviation is "+ 
		       computeStandardDeviationWithoutOutliers(values1, 10));
  }
  
}


